/*
** FireBugDetected
** @description: Если в браузере не существует консоли Firebug, то код добавляет его "пустышку" для предотвращения ошибок
** @author: Александр Кузнецов aka Regent(http://vl.vg/)
** @home_page: http://vl.vg/
*/
(
	function( window, top ){
		if( !window.console ){
			window.console = top.console && top.console.firebug ? top.console : {};
		}
		var
			names = [ 'log', 'debug', 'info', 'warn', 'error', 'assert', 'dir', 'dirxml', 'trace', 'group', 'groupCollapsed', 'groupEnd', 'time', 'timeEnd', 'profile', 'profileEnd', 'count' ],
			length = names.length,
			i = 0;
		for( ; i < length; i++ ){
			if( !window.console[ names[ i ] ] ){
				window.console[ names[ i ] ] = function(){};
			}
		}
	}
)( window, top );

/*
** jsam - JavaScript-Manager for admin
** @version 0.0.2beta1
** @description: JavaScript-инструментарий менеджера MODx для настройки внешнего вида панели администратора
** @author: Александр Николаевич Кузнецов aka Regent(http://vl.vg/)
** @temp_home_page: http://vj.vg/
** @this_type: General JavaScript code
** Dual licensed under the MIT and GPL licenses.
** - http://www.opensource.org/licenses/mit-license.php
** - http://www.gnu.org/copyleft/gpl.html
*/
(
	function( window, top, document, jsam ){
		
		/*
		** Добавление к объекту String метода trim
		** Метод удаляет отступы вначале и в конце
		*/
		if( !String.prototype.trim ){
			var trimExpr = '[\\x09\\x0A-\\x0D\\x20\\xA0\\u1680\\u180E\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+';
			trimExpr = new RegExp( '^' + trimExpr + '|' + trimExpr + '$', 'g' );
			String.prototype.trim = function(){
				return this.replace( trimExpr, '' );
			};
		}
		
		/*
		** Назначение основных переменных
		*/
		var
			
			// Быстрая ссылка на объект jQuery
			$, jQuery = $ = jsam.jQuery.noConflict(),
			
			// Быстрая ссылка на функцию jQuery.extend
			extend = $.extend,
			
			// Быстрая ссылка на консоль FireBug
			console = window.console,
			
			/*
			** Функция посылки сообщения в консоль
			** Вариант для быстрого доступа
			*/
			log = function(){
				console.log.apply( console, arguments );
			},
			
			// GLOBAL
			doc = $( document ),
			win = $( window ),
			
			// Переменные для различного использования
			temp, i, length,
			
			// Функция проверки типа переданного значения на число
			isNumber = function( a ){
				return !!( typeof a == 'number' || a instanceof Number );
			},
			// Функция проверки типа переданного значения на строку
			isString = function( a ){
				return !!( typeof a == 'string' || a instanceof String );
			},
			// Функция проверки типа переданного значения на число или строку
			isNS = function( a ){
				return isString( a ) || isNumber( a );
			},
			
			// Глобальный объект jsam
			jsam = window.jsam = extend(
				
				/*
				** @name:
				**   jsam
				** @path:
				**   jsam
				** @api:
				**   jsam( fn );
				** @description:
				**   Передать на выполнение функцию с правилами
				** @param "fn":
				**   Функция, выполняемая при загрузке фрейма. Функция содержит в себе правила
				** @returns:
				**   jsam
				** @example:
				**   jsam(function( data, jQuery, log ){
				**     if( data.id == 5 )
				**       this.tab.hide();
				**   });
				*/
				function( fn ){
					return fn && jsam.fns.push( fn ) && jsam;
				},
				
				// Прошлый объект window.jsam, как основа
				jsam,
				
				// Прикрепляемые свойства
				{
					
					/**************************************/
					/******** Статические свойства ********/
					/**************************************/
					
					/*
					** @name:
					**   version
					** @path:
					**   jsam => version
					** @api:
					**   jsam.version;
					** @description:
					**   Текущая версия плагина
					** @returns:
					**   String Object - версия плагина
					** @example:
					**  if( jsam.version.major < 1 ){ alert( 'Message'' ); };
					**  alert( jsam.version );
					*/
					version: extend(
						new String( '0.0.2beta1' ),
						{
							major      : 0,
							minor      : 0,
							pathlevel  : 2,
							identifier : 'beta1'
						}
					),
					
					/*
					** @name:
					**   langs
					** @path:
					**   jsam => langs
					** @api:
					**   jsam.langs;
					** @description:
					**   Объект с переводами фраз с русского языка на другие языки
					** @returns:
					**   Object
					** @example:
					**  jsam.langs[ 'Фраза' ];
					*/
					langs: {
						"JSAM успешно подключился во фрейм типа": {
							en: "JSAM successfully connected to the frame-type",
							fr: "JSAM correctement connecté au type de trame"
						},
						"Информация о фрейме": {
							en: "Information frame",
							fr: "Cadre de l'information"
						},
						"Тип фрейма": {
							en: "Frame Type",
							fr: "Type de trame"
						},
						"Ссылка": {
							en: "Link",
							fr: "Lien"
						},
						"ссылка": {
							en: "link",
							fr: "lien"
						},
						"Объект": {
							en: "Object"
						},
						"объект": {
							en: "object"
						},
						"Количество тегов во фрейме": {
							en: "Number of tags in a frame"
						},
						"Информация о версиях": {
							en: "Version information"
						},
						"Данные документа": {
							en: "Document data"
						},
						"Время выполнения правил": {
							en: "Time of rules"
						}
					},
					
					// Различные ссылки для быстрого доступа и объекты для хранения информации
					log: log, $: $, stack: {}, isString: isString, isNumber: isNumber, isNS: isNS,
					
					/*
					** @name:
					**   cssInlineBlock
					** @path:
					**   jsam => cssInlineBlock
					** @api:
					**   jsam.cssInlineBlock;
					** @description:
					**   Кроссбраузерное CSS свойство inline-block
					** @returns:
					**   String
					** @example:
					**  jsam.cssInlineBlock;
					*/
					cssInlineBlock: 'display:-moz-inline-stack;display:inline-block;_overflow:hidden;zoom:1;*display:inline;',
					
					/*
					** @name:
					**   fns
					** @path:
					**   jsam => fns
					** @api:
					**   jsam.fns;
					** @description:
					**   Массив функций с правилами, выполняемых при загрузке фрейма
					** @returns:
					**   Array
					** @example:
					**  jsam.fns[ 0 ]();
					*/
					fns: [],
					
					/*
					** @name:
					**   map
					** @path:
					**   jsam => map
					** @api:
					**   jsam.map;
					** @description:
					**   Ассоциативный массив карты документов. Формат: array[ documenyID ] = parentID
					** @returns:
					**   Object
					** @example:
					**  jsam.map[ 5 ];   // Получить ID родителя пятого документа
					**  jsam..length;    // Получить количество ресурсов
					*/
					map: jsam.map || {
						// Количество ресурсов
						length: 0,
						// Максимальный ID ресурса
						max: 0
					},
					
					/*
					** @name:
					**   widget
					** @path:
					**   jsam => widget
					** @api:
					**   jsam.widget;
					** @description:
					**   Ассоциативный массив виджетов
					** @returns:
					**   Object
					** @example:
					**  jsam.widjet.widjetName( {} );
					*/
					widget: {},
					
					/**************************************/
					/********* Управляющие функции ********/
					/**************************************/
					
					/*
					** @name:
					**   translate
					** @path:
					**   jsam => translate
					** @api:
					**   jsam.translate( phrase, lang );
					** @description:
					**   Перевод строки с русского языка на язык системы управления, либо на нужный язык
					** @param "phrase":
					**   Фраза для перевода
					** @param "lang":
					**   Язык, на который нужно перевести фразу. По умолчанию это язык системы управления
					** @returns:
					**   String
					** @example:
					**  jsam.translate( 'Фраза' );
					**  jsam.translate( 'Фраза', 'fr' );
					*/
					translate: function( phrase, lang ){
						return jsam.langs[ phrase ] && jsam.langs[ phrase ][ lang || jsam.lang ] || phrase;
					},
					
					/*
					** @name:
					**   larry
					** @path:
					**   jsam => larry
					** @api:
					**   jsam.larry( index, length );
					** @description:
					**   Получение валидной позиции элемента, исходя из количества элементов
					** @param "index":
					**   Положительное либо отрицательное число
					** @param "length":
					**   Количество элементов
					** @returns:
					**   Number - число. Новая валидная позиция элемента
					** @example:
					**   jsam.larry( 0, 25 );     // 0
					**   jsam.larry( 1, 25 );     // 0
					**   jsam.larry( 5, 25 );     // 4
					**   jsam.larry( -1, 25 );    // 24
					**   jsam.larry( -5, 25 );    // 19
					**   jsam.larry( 500, 25 );   // 24
					**   jsam.larry( -500, 25 );  // 0
					*/
					larry: function( index, length ){
						if( ( index = parseInt( index ) ) != 0 ){
							index = index < 0 ? length + index : index - 1;
						}
						return index < 0 ? 0 : index > length ? length - 1 : index;
					},
					
					/*
					** @name:
					**   getParent
					** @path:
					**   jsam => getParent
					** @api:
					**   jsam.getParent( id );
					** @description:
					**   Получение ID родителя ресурса
					** @param "id":
					**   ID ресурса
					** @returns:
					**   Number - ID ресурса-родителя
					** @example:
					**   jsam.getParent( 10 );     // Получить ID родителя ресурса с ID == 10. Пример возвращённый данных: 2
					*/
					getParent: function( id ){
						return jsam.map[ id ] || 0;
					},
					
					/*
					** @name:
					**   getParents
					** @path:
					**   jsam => getParents
					** @api:
					**   jsam.getParents( id );
					** @description:
					**   Получение списка ID родителей ресурса
					** @param "id":
					**   ID ресурса
					** @returns:
					**   Array - массив родителей
					** @example:
					**   jsam.getParents( 10 );     // Получить ID родителей ресурса с ID == 10. Пример возвращённый данных: [ 5, 2 ]
					*/
					getParents: function( id ){
						var map = [];
						while( id ){
							( id = jsam.map[ id ] ) && map.push( id );
						}
						return map;
					},
					
					/*
					** @name:
					**   isDocument
					** @path:
					**   jsam => isDocument
					** @api:
					**   jsam.isDocument( id );
					** @description:
					**   Проверка на существование определённого ресурса
					** @param "id":
					**   ID ресурса
					** @returns:
					**   Boolean - существует или не существует такой ресурс
					** @example:
					**   jsam.isDocument( 5282 );
					*/
					isDocument: function( id ){
						return typeof jsam.map[ id ] != 'undefined';
					},
					
					/*
					** @name:
					**   level
					** @path:
					**   jsam => level
					** @api:
					**   jsam.level( id );
					** @description:
					**   Узнать уровень вложенности ресурса
					** @param "id":
					**   ID ресурса
					** @returns:
					**   Number - уровень вложенности ресурса
					** @example:
					**   jsam.level( 124 );                 // Уровень вложенности ресурса с ID == 124 равен 3
					*/
					level: function( id ){
						return jsam.getParents( id ).length;
					},
					
					/*
					** @name:
					**   tab
					** @path:
					**   jsam => tab
					** @api:
					**   jsam.tab( tab );
					** @description:
					**   Получить Объект с набором функций для управления виджетом "Tab Pane 1.02(By Erik Arvidsson and for WebFX (http://webfx.eae.net/))"
					** @param "tab":
					**   НЕОБЯЗАТЕЛЬНО - Порядковый номер виджета "Tab Pane" в документе(отсчёт идёт с нуля) или DOM-объект - тег div с классом "tab-row"
					** @returns:
					**   Tab Object - объект для управления виджетом "Tab Pane"
					** @example:
					**   jsam.tab();           // Получить объект для управления первым в документе виджетом "Tab Pane"
					**   jsam.tab( 2 );        // Получить объект для управления третьим в документе виджетом "Tab Pane"
					*/
					tab: extend(
						function( tab ){
							return new jsam.tab.Class( tab );
						},
						{
							
							/*
							** @name:
							**   Class
							** @path:
							**   jsam => tab => Class
							** @api:
							**   new jsam.tab.Class( tab );
							** @description:
							**   Конструктор для получения объекта с набором функций для управления виджетом "Tab Pane"
							** @param "tab":
							**   НЕОБЯЗАТЕЛЬНО - Порядковый номер виджета "Tab Pane" в документе(отсчёт идёт с нуля) или DOM объект - тег div с классом "tab-row"w
							** @returns:
							**   Tab Object - объект для управления виджетом "Tab Pane"
							** @example:
							**   new jsam.tab.Class();           // Получить объект для управления первым в документе виджетом "Tab Pane"
							**   new jsam.tab.Class( 2 );        // Получить объект для управления третьим в документе виджетом "Tab Pane"
							*/
							'Class': extend(
								function( tab ){
									/*
									** Ссылка на таб(тег-контейнер div)
									** Обычно это тег с id == documentPane или классом tab-pane
									*/
									this.tab = isNumber( typeof tab == 'undefined' && ( tab = 0 ) ) ? $( 'div.tab-pane' ).eq( tab ) : $( tab );
									// Ссылка на "табы-открывашки". Другими словами на контейнер табов
									this.row = this.tab.find( '.tab-row:eq(0)' );
									// Ссылка на виджет "Tab Pane"
									this.pane = this.tab[ 0 ].tabPane;
								},
								{
									prototype: {
										
										/*
										** @name:
										**   tabs
										** @path:
										**   jsam => tab => Class => prototype => tabs
										** @api:
										**   jsam.tab().tabs();
										** @description:
										**   Получить все теги h2 - табы-кнопки(в дальнейшем просто "табы") текущего виджета(в дальнейшем термин "текущий виджет" опускается)
										** @returns:
										**   jQuery Object - табы
										** @example:
										**   jsam.tab().tabs();      // Получить все табы
										*/
										tabs: function(){
											return this.row.children( 'h2' );
										},
										
										/*
										** @name:
										**   get
										** @path:
										**   jsam => tab => Class => prototype => get
										** @api:
										**   jsam.tab().get( multiparams );
										** @description:
										**   Получить определённый(ные) таб(ы)
										** @param "multiparams":
										**   Номер таба(отсчёт идёт с первого) или его текст(пример: 1 или "Online"). Передаётся несколько строк или один массив строк
										** @returns:
										**   jQuery Object - таб(ы)
										** @example:
										**   jsam.tab().get();                     // Получить все табы
										**   jsam.tab().get( 1 );                  // Получить первый таб
										**   jsam.tab().get( 3, false );           // Получить третий и первый таб
										**   jsam.tab().get( -1 );                 // Получить последний таб
										**   jsam.tab().get( -2 );                 // Получить предпоследний таб
										**   jsam.tab().get( "Online" );           // Получить таб с текстом "Online"
										**   jsam.tab().get( -1, 4, "Online" );    // Получить последний и четвёртый табы, а также таб с текстом "Online"
										*/
										get: function(){
											var
												tabs = this.tabs(),
												length = tabs.size(),
												arr = arguments.length == 1 && typeof arguments[ 0 ] == 'object' ? arguments[ 0 ] : arguments;
											return !arr.length || ( arr.length == 1 && arr[ 0 ] == false ) ? tabs : $( arr )
												.map(
													function(){
														var id = this;
														return isNumber( id ) ? tabs.eq( jsam.larry( id, length ) )[ 0 ]
															: isString( id ) ?  tabs.filter( ':has( > span:contains("' + id.replace( /"/g, '\\"' ) + '"))' )[ 0 ]
															: tabs.first()[ 0 ];
													}
												);
										},
										
										/*
										** @name:
										**   box
										** @path:
										**   jsam => tab => Class => prototype => box
										** @api:
										**   jsam.tab().box( multiparams );
										** @description:
										**   Получить содержимое определённого(ных) таба(ов)
										** @param "multiparams":
										**   Номер таба(отсчёт идёт с первого) или его текст(пример: 1 или "Online"). Передаётся несколько строк или один массив строк
										** @returns:
										**   jQuery Object - контейнер содержимого таба
										** @example:
										**   jsam.tab().box();                     // Получить содержимое всех табов
										**   jsam.tab().box( 1 );                  // Получить содержимое первого таба
										**   jsam.tab().box( 3, false );           // Получить содержимое третьего и первого табов
										**   jsam.tab().box( -1 );                 // Получить содержимое последнего таба
										**   jsam.tab().box( -2 );                 // Получить содержимое предпоследнего таба
										**   jsam.tab().box( "Online" );           // Получить содержимое таба с текстом "Online"
										**   jsam.tab().box( -1, 4, "Online" );    // Получить содержимое последнего и четвёртого табов, а также содержимое таба с текстом "Online"
										*/
										box: function(){
											var p = this.pane.pages;
											return this.get.call( this, arguments )
												.map(
													function(){
														var _this = this, box;
														$.each(
															p,
															function(){
																if( this.tab == _this ){
																	box = this.element;
																}
															}
														);
														return box;
													}
												);
										},
										
										/*
										** @name:
										**   select
										** @path:
										**   jsam => tab => Class => prototype => select
										** @api:
										**   jsam.tab().select( tab );
										** @description:
										**   Выбрать(кликнуть) определённый таб
										** @param "tab":
										**   Номер таба(отсчёт идёт с первого) или его текст(пример: 5 или "Online")
										** @returns:
										**   jQuery Object - выбранный таб
										** @example:
										**   jsam.tab().select();                  // Выбрать первый таб
										**   jsam.tab().select( 3 );               // Выбрать третий таб
										**   jsam.tab().select( -1 );              // Выбрать последний таб
										*/
										select: function(){
											return this.get( arguments )
												.filter(
													function(){
														return $( this ).css( 'display' ) != 'none';
													}
												)
												.first()
												.click();
										},
										
										/*
										** @name:
										**   hide
										** @path:
										**   jsam => tab => Class => prototype => hide
										** @api:
										**   jsam.tab().hide( multiparams );
										** @description:
										**   Скрыть таб(ы)
										** @param "multiparams":
										**   Номер таба(отсчёт идёт с первого) или его текст(пример: 1 или "Online"). Передаётся несколько строк или один массив строк
										** @returns:
										**   jQuery Object - скрытый таб(ы)
										** @example:
										**   jsam.tab().hide();                  // Скрыть все табы
										**   jsam.tab().hide( 3 );               // Скрыть третий таб
										*/
										hide: function(){
											var tabs = this.get( arguments ).hide();
											return this.box( arguments ).hide() && this.select() && tabs;
										},
										
										/*
										** @name:
										**   add
										** @path:
										**   jsam => tab => Class => prototype => add
										** @api:
										**   jsam.tab().add( name, content, index );
										** @description:
										**  Добавить новый таб
										** @param "name":
										**   Название таба(обязательно)(HTML-разметка разрешена)
										** @param "content":
										**   Контент таба(необязательно)(HTML-разметка разрешена)
										** @param "index":
										**   Позиция таба(необязательно)(Число)
										** @param "sectionStyle":
										**   Оформлять ли в стиль секции?(По умолчанию true)
										** @returns:
										**   jQuery Object - добавленный таб
										** @example:
										**   jsam.tab().add( "Money" );                         // Добавить таб с названием "Money" в конечную позицию
										**   jsam.tab().add( "Money", "For people<br>:)" );     // Добавить таб с названием "Money" и контентом "For people<br>:)" в конечную позицию
										**   jsam.tab().add( "Money", "For people<br>:)", 3 );  // Добавить таб с названием "Money" и контентом "For people<br>:)" в третью позицию
										**   jsam.tab().add( "Money", false, 3 );               // Добавить таб с названием "Money" в третью позицию
										*/
										add: function( name, content, index, sectionStyle ){
											var tab = $( '<div class="tab-page"><h2 class="tab">' + name + '</h2></div>' );
											this.row.after( tab );
											this.pane.addTabPage( tab[ 0 ] );
											tab.append(
												sectionStyle == false ? content
												: $( '<div><div class="sectionHeader">' + name + '</div><div class="sectionBody"></div></div>' ).find( '.sectionBody' ).append( content || '' ).parent()
											);
											return isNumber( index ) ? this.move( name, index ) : this.get( name );
										},
										
										/*
										** @name:
										**   move
										** @path:
										**   jsam => tab => Class => prototype => move
										** @api:
										**   jsam.tab().move( tab, index );
										** @description:
										**   Переместить таб в определённую позицию
										** @param "tab":
										**   Номер таба(отсчёт идёт с первого) или его текст(пример: 1 или "Online")
										** @param "index":
										**   Новая позиция таба(необязательно)
										** @returns:
										**   jQuery Object - перемещённый таб
										** @example:
										**   jsam.tab().move( 3 );            // Переместить третий таб в конечную позицию
										**   jsam.tab().move( 3, 1 );         // Переместить третий таб в первую позицию
										*/
										move: function( tab, index ){
											var tab = this.get( tab ).detach();
											!isNumber( index ) ? this.row.append( tab ) : this.get( index ).eq( 0 ).before( tab );
											this.select();
											return tab;
										},
										
										/*
										** @name:
										**   rename
										** @path:
										**   jsam => tab => Class => prototype => rename
										** @api:
										**   jsam.tab().rename( tab, name );
										** @description:
										**   Переименовать таб
										** @param "tab":
										**   Номер таба(отсчёт идёт с первого) или его текст(пример: 1 или "Online")
										** @param "name":
										**   Новое название таба(HTML-разметка разрешена)
										** @returns:
										**   jQuery Object - переименованный таб
										** @example:
										**   jsam.tab().rename( 3, "LoL" );            // Переименовать третий таб в "LoL"
										*/
										rename: function( tab, name ){
											return this.get( tab )
												.each(
													function(){
														var span = $( this ).children( 'span' );
														span.add( $( 'div.sectionHeader:contains("' + span.text().replace( /"/g, '\\"' ) + '")'  ) ).html( name );
													}
												);
										}
										
									}
								}
							)
						}
					),
					
					/**************************************************/
					/***** Набор объектов для управления фреймами *****/
					/**************************************************/
					
					/*
					** @name:
					**   menu
					** @path:
					**   jsam => menu
					** @api:
					**   jsam.menu( fn );
					** @description:
					**   Передать на выполнение функцию с правилами настройки МЕНЮ АДМИНИСТРАТИВНОЙ ПАНЕЛИ. Функция выполняется только в фрейме типа "menu"
					** @param "fn":
					**   Функция, выполняемая при загрузке фрейма типа "menu". Функция содержит в себе правила нстройки
					** @returns:
					**   jsam.menu
					** @example:
					**   jsam.menu(function( data, jQuery, log ){
					**     this.tab.hide( 1 );
					**   });
					*/
					menu: extend(
						
						function( fn ){
							return fn && jsam.fns.push( function( data ){ data.type == 'menu' && fn.apply( this, arguments ); } ) && jsam.menu;
						},
						{
							
							/*
							** @name:
							**   tab
							** @path:
							**   jsam => menu => tab
							** @api:
							**   jsam.menu.tab( id );
							** @description:
							**   Получить один или несколько табов меню
							** @param "id":
							**   Номер таба(отсчёт идёт с первого) или его название(пример: 1 или "Сайт")
							** @returns:
							**   jQuery Object - таб(ы)
							** @example:
							**   jsam.menu.tab();                      // Получить все табы
							**   jsam.menu.tab( 1 );                   // Получить первый таб
							**   jsam.menu.tab( 3, false );            // Получить третий и первый таб
							**   jsam.menu.tab( -1 );                  // Получить последний таб
							**   jsam.menu.tab( -2 );                  // Получить предпоследний таб
							**   jsam.menu.tab( "Security" );          // Получить таб с названием "Security"
							**   jsam.menu.tab( -1, 1, "Security" );   // Получить последний и первый табы, а также таб с названием "Security"
							*/
							tab: extend(
								function( id ){
									var
										tabs = jsam.menu.nav.children( 'li' ),
										size = tabs.size(),
										arr = arguments.length == 1 && typeof arguments[ 0 ] == 'object' ? arguments[ 0 ] : arguments;
									return !arr.length || ( arr.length == 1 && arr[ 0 ] == false ) ? tabs : $( arr )
										.map(
											function(){
												var id = this;
												return isNumber( id ) ? tabs.get( jsam.larry( id, size ) )
													: isString( id ) ? tabs.filter( ':has( > a:contains("' + id.replace( /"/g, '\\"' ) + '"))' )[ 0 ]
													: tabs.get( 0 );
											}
										);
								},
								{
									
									/*
									** @name:
									**   hide
									** @path:
									**   jsam => menu => tab => hide
									** @api:
									**   jsam.menu.tab.hide( id );
									** @description:
									**   Скрыть из виду один или несколько табов меню
									** @param "id":
									**   Номер таба(отсчёт идёт с первого) или его название(пример: 1 или "Сайт"). Один массив строк или несколько строк
									** @returns:
									**   jQuery Object - скрытый таб(ы)
									** @example:
									**   jsam.menu.tab.hide();                      // Скрыть все табы
									**   jsam.menu.tab.hide( 1 );                   // Скрыть первый таб
									**   jsam.menu.tab.hide( 3, false );            // Скрыть третий и первый таб
									**   jsam.menu.tab.hide( -1 );                  // Скрыть последний таб
									**   jsam.menu.tab.hide( -2 );                  // Скрыть предпоследний таб
									**   jsam.menu.tab.hide( "Security" );          // Скрыть таб с названием "Security"
									**   jsam.menu.tab.hide( -1, 1, "Security" );   // Скрыть последний и первый табы, а также таб с названием "Security"
									*/
									hide: function( id ){
										var tabs = jsam.menu.tab.apply( this, arguments ).hide();
										jsam.menu.tab().removeClass( 'active' ).filter( ':visible:first' ).addClass( 'active' );
										return tabs;
									},
									
									/*
									** @name:
									**   remove
									** @path:
									**   jsam => menu => tab => remove
									** @api:
									**   jsam.menu.tab.remove( id );
									** @description:
									**   Удалить из документа один или несколько табов меню
									** @param "id":
									**   Номер таба(отсчёт идёт с первого) или его название(пример: 1 или "Сайт"). Один массив строк или несколько строк
									** @returns:
									**   jQuery Object - удалённый таб(ы) с помощью метода detach
									** @example:
									**   jsam.menu.tab.remove();                      // Удалить все табы
									**   jsam.menu.tab.remove( 1 );                   // Удалить первый таб
									**   jsam.menu.tab.remove( 3, false );            // Удалить третий и первый таб
									**   jsam.menu.tab.remove( -1 );                  // Удалить последний таб
									**   jsam.menu.tab.remove( -2 );                  // Удалить предпоследний таб
									**   jsam.menu.tab.remove( "Security" );          // Удалить таб с названием "Security"
									**   jsam.menu.tab.remove( -1, 1, "Security" );   // Удалить последний и первый табы, а также таб с названием "Security"
									*/
									remove: function( id ){
										return jsam.menu.tab.hide.apply( this, arguments ).detach();
									},
									
									/*
									** @name:
									**   rename
									** @path:
									**   jsam => menu => tab => rename
									** @api:
									**   jsam.menu.tab.rename( id, html );
									** @description:
									**   Переименовать один или несколько табов
									** @param "id":
									**   Номер таба(отсчёт идёт с первого) или его название(пример: 1 или "Сайт"). Это массив строк/чисел либо одна строка/число
									** @param "name":
									**   Новое название таба(HTML-разметка разрешена)
									** @returns:
									**   jQuery Object - переименованный таб(ы)
									** @example:
									**   jsam.menu.tab.rename( 1, "Info" );                   // Переименовать первый таб в "Info"
									**   jsam.menu.tab.rename( "Elements", "More" );          // Переименовать таб "Elements" в "More"
									**   jsam.menu.tab.rename( [ -1, "Modules" ], "Other" );  // Переименовать последний таб и таб "Modules" в "Other"
									*/
									rename: function( id, name ){
										return jsam.menu.tab( id ).children( 'a' ).html( name ).parent();
									},
									
									/*
									** @name:
									**   add
									** @path:
									**   jsam => menu => tab => add
									** @api:
									**   jsam.menu.tab.add( name, index );
									** @description:
									**   Добавить новый таб в определённую позицию
									** @param "name":
									**   Название таба(HTML-разметка разрешена)
									** @param "index":
									**   Позиция таба(необязательно)
									** @param "content":
									**   Контент таба(необязательно)
									** @returns:
									**   jQuery Object - добавленный таб
									** @example:
									**   jsam.menu.tab.add( "Team" );      // Добавить таб "Team" в конечную позицию
									**   jsam.menu.tab.add( "Team", 5 );   // Добавить таб "Team" в пятую позицию
									*/
									add: function( name, index, content ){
										var
											id = ( Math.random() * +new Date() ).toString().substr( 0, 5 ),
											tab = $(
												'<li id="limenu' + id + '">'
													+ '<a onclick="new NavToggle( this ); return false;" href="#menu' + id + '">' + name + '</a>'
													+ '<ul id="menu' + id + '" class="subnav">' + ( content || '' ) + '</ul>'
												+ '</li>'
											),
											tabs = jsam.menu.nav.children( 'li' );
										!isNumber( index ) ? jsam.menu.nav.append( tab ) : tabs.eq( jsam.larry( index, tabs.size() ) ).before( tab );
										return tab;
									},
									
									/*
									** @name:
									**   move
									** @path:
									**   jsam => menu => tab => move
									** @api:
									**   jsam.menu.tab.move( id, index );
									** @description:
									**   Переместить таб(ы) в определённую позицию
									** @param "id":
									**   Номер таба(отсчёт идёт с первого) или его название(пример: 1 или "Сайт"). Это массив строк/чисел либо одна строка/число
									** @param "index":
									**   Новая позиция таба(необязательно)
									** @returns:
									**   jQuery Object - перемещённый таб(ы)
									** @example:
									**   jsam.menu.tab.move( 3 );               // Переместить третий таб в конец
									**   jsam.menu.tab.move( 3, 2 );            // Переместить третий таб на вторую позицию
									**   jsam.menu.tab.move( [ -1, -2 ], 2 );   // Переместить последний и предпоследний табы в начальную позицию
									**   jsam.menu.tab.move( [ 1, 2 ] );        // Переместить первый и второй табы в конечную позицию
									*/
									move: function( id, index ){
										var
											tab = jsam.menu.tab.hide( id ).detach().show(),
											tabs = jsam.menu.nav.children( 'li' ),
											size = tabs.size();
										!isNumber( index ) ? jsam.menu.nav.append( tab ) : tabs.eq( jsam.larry( index, size ) ).before( tab );
										return tab;
									}
									
								}
							),
							
							/*
							** @name:
							**   link
							** @path:
							**   jsam => menu => link
							** @api:
							**   jsam.menu.link( link, tab );
							** @description:
							**   Получить определённую ссылку из таба
							** @param "tab":
							**   Номер таба(отсчёт идёт с первого) или его название. Например это число 1 или строка "Site"
							** @param "link":
							**   Номер ссылки(отсчёт идёт с первой) в табе меню или её текст. Например это число 1 или строка "Home"
							** @returns:
							**   jQuery Object - определённая ссылка из таба меню
							** @example:
							**   jsam.menu.link();                         // Получить все ссылки табов
							**   jsam.menu.link( false, 2 );               // Получить все ссылки второго таба
							**   jsam.menu.link( 2, 2 );                   // Получить вторую ссылку второго таба
							**   jsam.menu.link( [ 1, 2 ] );               // Получить первую и вторую ссылку из всех ссылок
							**   jsam.menu.link( [ 1, -1 ], -1 );          // Получить первую и последнюю ссылку последнего таба
							**   jsam.menu.link( [ 1, -2 ], [ 2, -2 ] );   // Получить первую и предпоследнюю ссылку из ссылок второго и предпоследнего таба
							**   jsam.menu.link( "Backup" );               // Получить ссылку с названием "Backup"
							**   jsam.menu.link( 4, "Site" );              // Получить четвёртую ссылку в табе с текстом "Site"
							*/
							link: extend(
								function( link, tab ){
									var
										links = ( arguments.length > 1 ? jsam.menu.tab( tab ) : jsam.menu.nav.children( 'li' ) ).find( ' > ul > li > a ' ),
										size = links.size(),
										arr = isNS( link ) ? [ link ] : typeof link == 'object' && link.length ? link : [];
									return !arr.length || ( arr.length == 1 && arr[ 0 ] == false ) ? links : $( arr )
										.map(
											function(){
												var id = this;
												return isNumber( id ) ? links.get( jsam.larry( id, size ) )
													: isString( id ) ? links.filter( ':contains("' + id.replace( /"/g, '\\"' ) + '")' )[ 0 ]
													: tabs.get( 0 );
											}
										);
								},
								{
									
									/*
									** @name:
									**   add
									** @path:
									**   jsam => menu => link => add
									** @api:
									**   jsam.menu.link.add( tab, html, path );
									** @description:
									**   Добавить новую ссылку в таб
									** @param "tab":
									**   Номер таба(отсчёт идёт с первого) или его название. Пример: число 1 или строка "Site"
									** @param "name":
									**   Название ссылки(HTML-разметка разрешена)
									** @param "path":
									**   Адрес ссылки(необязательно)
									** @returns:
									**   jQuery Object - созданная и добавленная ссылка
									** @example:
									**   jsam.menu.link.add( 1, "Edit footer", "index.php?id=1&a=78" );         // Добавить ссылку в первый таб с названием "Edit footer", ведущую на адрес "index.php?id=1&a=78"
									**   jsam.menu.link.add( "Elements", "Template", "index.php?id=3&a=16" );   // Добавить ссылку в таб "Elements" с названием "Template", ведущую на адрес "index.php?id=3&a=16"
									*/
									add: function( tab, name, path ){
										return $( '<li><a target="main" href="' + ( path || '?a=2' ) + '" onclick="this.blur();">' + ( name || '' ) + '</a></li>' )
											.appendTo( jsam.menu.tab( tab ).children( 'ul.subnav' ) );
									},
									
									/*
									** @name:
									**   rename
									** @path:
									**   jsam => menu => link => rename
									** @api:
									**   jsam.menu.link.rename( tab, link, name, path );
									** @description:
									**   Переименовать определённую ссылку
									** @param "tab":
									**   Номер таба(отсчёт идёт с первого) или его название. Пример: число 1 или строка "Site"
									** @param "link":
									**   Номер ссылки(отсчёт идёт с первой) в табе меню или её текст. Пример: число 1 или строка "Home"
									** @param "name":
									**   Новое название ссылки(HTML-разметка разрешена)
									** @param "path":
									**   Новый адрес ссылки(необязательно)
									** @returns:
									**   jQuery Object - переименованная ссылка
									** @example:
									**   jsam.menu.link.rename( 1, 1, "Tutorial" );                 // Переименовать первую ссылку в первом табе в текст "Tutorial"
									**   jsam.menu.link.rename( "Backup", "Tools", "Download" );    // Переименовать ссылку "Backup" в табе "Tools" в название "Download"
									**   jsam.menu.link.rename( 2, 2, false, "index.php?a=2" );     // Изменить адрес у второй ссылки во втором табе на "index.php?a=2"
									**   jsam.menu.link.rename( 1, 2, "Info", "index.php?a=2" );    // Переименовать вторую ссылку в четвёртом табе в текст "Info" и изменить адрес на "index.php?a=2"
									*/
									rename: function( link, tab, html, path ){
										link = jsam.menu.link( link, tab );
										arguments.length > 2 && html != false && link.html( html );
										arguments.length > 3 && path != false && link.attr( 'href', path );
										return link;
									},
									
									/*
									** @name:
									**   move
									** @path:
									**   jsam => menu => link => move
									** @api:
									**   jsam.menu.link.move( link, tab, index, newTab );
									** @description:
									**   Переместить ссылку в определённую позицию  в определённом табе
									** @param "tab":
									**   Номер таба(отсчёт идёт с первого) или его название. Пример: число 1 или строка "Site"
									** @param "link":
									**   Номер ссылки(отсчёт идёт с первой) в табе или её текст. Пример: число 1 или строка "Home"
									** @param "index":
									**   Новая позиция ссылки(необязательно)
									** @param "newTab":
									**   Номер таба(отсчёт идёт с первого) или его название. В этот таб перемещается ссылка. Пример: число 1 или строка "Site". Необязательно
									** @returns:
									**   jQuery Object - перемещённая ссылка
									** @example:
									**   jsam.menu.link.move( 1 );                  // Переместить первую ссылку первого таба в конечную позицию
									**   jsam.menu.link.move( 1, 2 );               // Переместить первую ссылку второго таба в конечную позицию
									**   jsam.menu.link.move( 1, 2, 2 );            // Переместить первую ссылку второго таба во вторую позицию
									**   jsam.menu.link.move( 1, 2, 2, 1 );         // Переместить первую ссылку второго таба во вторую позицию первого таба
									**   jsam.menu.link.move( 1, 2, false, 1 );     // Переместить первую ссылку второго таба в конечную позицию первого таба
									*/
									move: function( link, tab, index, newTab ){
										var
											li = jsam.menu.link( link, tab ).parent(),
											ul = arguments.length > 3 ? jsam.menu.tab( newTab ).children( 'ul' ) : li.parent(),
											_li;
										li.detach();
										isNumber( index ) ? ( _li = ul.children( 'li' ) ).eq( jsam.larry( index, _li.size() ) ).before( li ) : ul.append( li );
										return li;
									},
									
									/*
									** @name:
									**   hide
									** @path:
									**   jsam => menu => link => hide
									** @api:
									**   jsam.menu.link.hide( link, tab );
									** @description:
									**   Скрыть из виду ссылку(и) в табе(ах)
									** @param "tab":
									**   Номер таба(отсчёт идёт с первого) или его название. Пример: число 1 или строка "Site" или массив [ 2, "Site" ]
									** @param "link":
									**   Номер ссылки(отсчёт идёт с первой) в табе или её текст. Пример: число 1 или строка "Home" или массив [ 2, "Home" ]
									** @returns:
									**   jQuery Object - контейнеры скрытых ссылок
									** @example:
									**   jsam.menu.link.hide();                         // Скрыть все ссылки табов
									**   jsam.menu.link.hide( false, 2 );               // Скрыть все ссылки второго таба
									**   jsam.menu.link.hide( 2, 2 );                   // Скрыть вторую ссылку второго таба
									**   jsam.menu.link.hide( [ 1, 2 ] );               // Скрыть первую и вторую ссылку из всех ссылок
									**   jsam.menu.link.hide( [ 1, -1 ], -1 );          // Скрыть первую и последнюю ссылку последнего таба
									**   jsam.menu.link.hide( [ 1, -2 ], [ 2, -2 ] );   // Скрыть первую и предпоследнюю ссылку из ссылок второго и предпоследнего таба
									**   jsam.menu.link.hide( "Backup" );               // Скрыть ссылку с названием "Backup"
									**   jsam.menu.link.hide( 4, "Site" );              // Скрыть четвёртую ссылку в табе с текстом "Site"
									*/
									hide: function( link, tab ){
										return jsam.menu.link.apply( this, arguments ).parent().hide();
									},
									
									/*
									** @name:
									**   remove
									** @path:
									**   jsam => menu => link => remove
									** @api:
									**   jsam.menu.link.remove( link, tab );
									** @description:
									**   Удалить из виду ссылку(и) в табе(ах)
									** @param "tab":
									**   Номер таба(отсчёт идёт с первого) или его название. Пример: число 1 или строка "Site" или массив [ 2, "Site" ]
									** @param "link":
									**   Номер ссылки(отсчёт идёт с первой) в табе или её текст. Пример: число 1 или строка "Home" или массив [ 2, "Home" ]
									** @returns:
									**   jQuery Object - контейнеры удалённых ссылок
									** @example:
									**   jsam.menu.link.remove();                         // Удалить все ссылки табов
									**   jsam.menu.link.remove( false, 2 );               // Удалить все ссылки второго таба
									**   jsam.menu.link.remove( 2, 2 );                   // Удалить вторую ссылку второго таба
									**   jsam.menu.link.remove( [ 1, 2 ] );               // Удалить первую и вторую ссылку из всех ссылок
									**   jsam.menu.link.remove( [ 1, -1 ], -1 );          // Удалить первую и последнюю ссылку последнего таба
									**   jsam.menu.link.remove( [ 1, -2 ], [ 2, -2 ] );   // Удалить первую и предпоследнюю ссылку из ссылок второго и предпоследнего таба
									**   jsam.menu.link.remove( "Backup" );               // Удалить ссылку с названием "Backup"
									**   jsam.menu.link.remove( 4, "Site" );              // Удалить четвёртую ссылку в табе с текстом "Site"
									*/
									remove: function( link, tab ){
										return jsam.menu.link.apply( this, arguments ).parent().detach();
									}
									
								}
							)
							
						}
					),
					
					/*
					** @name:
					**   home
					** @path:
					**   jsam => home
					** @api:
					**   jsam.home( fn );
					** @description:
					**   Передать на выполнение функцию с правилами. Функция выполняется только во фрейме типа "home"
					** @param "fn":
					**   Функция, выполняемая при загрузке фрейма типа "home". Функция содержит в себе правила нстройки
					** @returns:
					**   jsam.home
					** @example:
					**   jsam.home(function( data, jQuery, log ){
					**     this.tab.hide( 1 );
					**   });
					*/
					home: extend(
						
						function( fn ){
							return fn && jsam.fns.push( function( data ){ data.type == 'home' && fn.apply( this, arguments ); } ) && jsam.home;
						},
						{
							
							/*
							** @name:
							**   inbox
							** @path:
							**   jsam => home => inbox
							** @api:
							**   jsam.home.inbox();
							** @description:
							**   Получить раздел сообщений
							** @returns:
							**   jQuery Object - контейнеры раздела сообщений
							** @example:
							**   jsam.home.inbox();
							*/
							inbox: extend(
								function(){
									var
										img = $( 'a[href="index.php?a=10"]:has( > img )' ),
										name = img.next( 'span' ),
										comment = name.next().next();
									return img.add( name ).add( comment );
								},
								{
									
									/*
									** @name:
									**   hide
									** @path:
									**   jsam => home => inbox => hide
									** @api:
									**   jsam.home.inbox.hide();
									** @description:
									**   Скрыть раздел сообщений
									** @returns:
									**   jQuery Object - скрытые контейнеры раздела сообщений
									** @example:
									**   jsam.home.inbox.hide();
									*/
									hide: function(){
										return jsam.home.inbox().hide();
									}
									
								}
							),
							
							/*
							** @name:
							**   button
							** @path:
							**   jsam => home => button
							** @api:
							**   jsam.home.button( id );
							** @description:
							**   Получить кнопку(и) вариаций на главной странице в первой вкладке
							** @param "id":
							**   Номер кнопки(отсчёт идёт с первого) или её название. Пример: число 1 или строка "Modules" или массив [ -1, "Modules" ]
							** @returns:
							**   jQuery Object - кнопка
							** @example:
							**   jsam.home.button();                    // Получить все кнопки
							**   jsam.home.button( 1 );                 // Получить первую кнопку
							**   jsam.home.button( -1 );                // Получить последнюю кнопку
							**   jsam.home.button( "Modules" );         // Получить кнопку с названием "Modules"
							**   jsam.home.button( 2, -2, "Modules" );  // Получить вторую и предпоследнюю кнопку, а также кнопку с названием "Modules"
							*/
							button: extend(
								function(){
									var
										buttons = $( 'span.wm_button' )
										size = buttons.size(),
										arr = arguments.length == 1 && typeof arguments[ 0 ] == 'object' ? arguments[ 0 ] : arguments;
									return !arr.length || ( arr.length == 1 && arr[ 0 ] == false ) ? buttons : $( arr )
										.map(
											function(){
												var id = this;
													return isNumber( id ) ? buttons.get( jsam.larry( id, size ) )
														: isString( id ) ? buttons.filter( ':has( > a:contains("' + id.replace( /"/g, '\\"' ) + '"))' )[ 0 ]
														: buttons.get( 0 );
											}
										);
								},
								{
									
									/*
									** @name:
									**   hide
									** @path:
									**   jsam => home => hide
									** @api:
									**   jsam.home.button.hide( id );
									** @description:
									**   Скрыть кнопку(и) вариаций на главной странице в первой вкладке
									** @param "id":
									**   Номер кнопки(отсчёт идёт с первого) или её название. Пример: число 1 или строка "Modules" или массив [ -1, "Modules" ]
									** @returns:
									**   jQuery Object - скрытая кнопка(и)
									** @example:
									**   jsam.home.button.hide();                    // Скрыть все кнопки
									**   jsam.home.button.hide( 1 );                 // Скрыть первую кнопку
									**   jsam.home.button.hide( -1 );                // Скрыть последнюю кнопку
									**   jsam.home.button.hide( "Modules" );         // Скрыть кнопку с названием "Modules"
									**   jsam.home.button.hide( 2, -2, "Modules" );  // Скрыть вторую и предпоследнюю кнопку, а также кнопку с названием "Modules"
									*/
									hide: function(){
										return jsam.home.button.apply( this, arguments ).hide();
									},
									
									/*
									** @name:
									**   move
									** @path:
									**   jsam => home => move
									** @api:
									**   jsam.home.button.move( id, index );
									** @description:
									**   Переместить кнопку в определённую позицию
									** @param "id":
									**   Номер кнопки(отсчёт идёт с первого) или её название. Пример: число 1 или строка "Modules" или массив [ -1, "Modules" ]
									** @returns:
									**   jQuery Object - перемещённая кнопка(и)
									** @example:
									**   jsam.home.button.move( 1 );                    // Переместить первую кнопку в конечную позицию
									**   jsam.home.button.move( 2, 1 );                 // Переместить вторую кнопку на первую позицию
									**   jsam.home.button.move( "Modules" );            // Переместить кнопку "Modules" в конечную позицию
									*/
									move: function( id, index ){
										var
											button = jsam.home.button( id ).detach(),
											buttons = jsam.home.button();
										!isNumber( index ) ? buttons.last().after( button ) :  buttons.eq( jsam.larry( index, buttons.size() ) ).before( button );
										return button;
									},
									
									/*
									** @name:
									**   add
									** @path:
									**   jsam => home => add
									** @api:
									**   jsam.home.button.add( name, path, img, index )
									** @description:
									**   Добавить новую кнопку
									** @param "name":
									**   Название кнопки(HTML-разметка разрешена)
									** @param "path":
									**   Url-адрес, на который ведёт кнопка(необязательно)
									** @param "img":
									**   Url-адрес изображения кнопки(необязательно)
									** @param "index":
									**   Позиция кнопки(необязательно)
									** @returns:
									**   jQuery Object - добавленная кнопка
									** @example:
									**   jsam.home.button.add( "Footer", "?a=78&id=1" );
									**     // Добавить кнопку с названием "Footer" и адресом "?a=78&id=1"
									**
									**   jsam.home.button.add( "Footer", "?a=78&id=1", "circlerightarrow" );
									**     // Добавить кнопку с названием "Footer", адресом "?a=78&id=1" и изображением с названием "circlerightarrow", которое находится в папке media/style/MODxCarbon/images/icons/
									**
									**   jsam.home.button.add( "Footer", "?a=78&id=1", "media/browser/mcpuk/images/icons/32/cs.gif" );
									**     // Добавить кнопку с названием "Footer", адресом "?a=78&id=1" и изображением с адресом "media/browser/mcpuk/images/icons/32/cs.gif"
									**
									**   jsam.home.button.add( "Footer", "?a=78&id=1", "media/browser/mcpuk/images/toolbar/rotate.gif", 1 );
									**     // Добавить кнопку с названием "Footer", адресом "?a=78&id=1" и изображением с адресом "media/browser/mcpuk/images/icons/32/cs.gif" в начальную позицию
									*/
									add: function( name, path, img, index ){
										var
											button = $(
											'<span style="border: 0pt none;" class="wm_button">'
												+ '<a href="' + ( path || '' ) + '" class="hometblink">'
													+ '<img alt="' + name + '" src="'
															+ ( isString( img ) ? img.indexOf( '/' ) == -1 ? 'media/style/MODxCarbon/images/icons/' + img + '.gif' : img : 'media/style/MODxCarbon/images/tree/empty.gif" style="width:32px;height:32px;' )
														+ '">'
													+ '<br>'
													+ name
												+ '</a>'
											+ '</span>'
										),
											buttons = jsam.home.button();
										!isNumber( index ) ? buttons.last().after( button ) :  buttons.eq( jsam.larry( index, buttons.size() ) ).before( button );
										return button;
									},
									
									/*
									** @name:
									**   rename
									** @path:
									**   jsam => home => rename
									** @api:
									**   jsam.home.button.rename( id, name, path );
									** @description:
									**   Переименовать кнопку
									** @param "id":
									**   Номер кнопки(отсчёт идёт с первого) или её название. Пример: число 1 или строка "Modules" или массив [ -1, "Modules" ]
									** @param "name":
									**   Новое название кнопки(HTML-разметка разрешена)(необязательно)
									** @param "path":
									**   Новый url-адрес, на который указывает кнопка(необязательно)
									** @returns:
									**   jQuery Object - переименованная кнопка
									** @example:
									**   jsam.home.button.rename( 1, "LoL" );                         // Переименовать первую кнопку в "LoL"
									**   jsam.home.button.rename( 1, false, "?a=2" );                 // Сменить адрес первой кнопки на "?a=2"
									**   jsam.home.button.rename( 4, "Edit footer", "?a=78&id=1" );   // Переименовать четвёртую кнопку в "Edit footer" и сменить адрес на "?a=78&id=1"
									*/
									rename: function( id, name, path ){
										return jsam.home.button( id )
											.each(
												function(){
													var a = $( this ).find( 'a' )
													name && a.html( a.html().replace( /<br\s*\/?>(\s|.)+$/, '<br>' + name ) );
													path && a.attr( 'href', path );
												}
											);
									}
									
								}
							)
							
						}
					),
					
					/*
					** @name:
					**   document
					** @path:
					**   jsam => document
					** @api:
					**   jsam.document( fn );
					** @description:
					**   Передать на выполнение функцию с правилами. Функция выполняется только во фрейме типа "document"
					** @param "fn":
					**   Функция, выполняемая при загрузке фрейма типа "document". Функция содержит в себе правила нстройки фрейма
					** @returns:
					**   jsam.document
					** @example:
					**   jsam.document(function( data, jQuery, log ){
					**     this.tab.hide( 1 );
					**   });
					*/
					document: extend(
						
						function( fn ){
							return fn && jsam.fns.push( function( data ){ data.type == 'document' && fn.apply( this, arguments ); } ) && jsam.document;
						},
						{
							
							/*
							** @name:
							**   field
							** @path:
							**   jsam => document => field
							** @api:
							**   jsam.document.field( id );
							** @description:
							**   Получить поле(я) по его(их) имени
							** @param "id":
							**   Название поля или массив названий полей. Пример: "Title" или [ "Description", "Resource content" ]
							** @returns:
							**   jQuery Object - тег tr(контейнер поля. Далее просто "поле")
							** @example:
							**   jsam.document.field();                                              // Получить все поля
							**   jsam.document.field( "Title" );                                     // Получить поле с названием "Title"
							**   jsam.document.field( [ "URL alias", "Summary (introtext)" ] );      // Получить поля с названиями "URL alias" и "Summary (introtext)"
							**   jsam.document.field( "Title", "Resource content", "Description" );  // Получить поля с названиями "Title", "Resource content", "Description"
							*/
							field: extend(
								function( field ){
									var
										arr = arguments.length == 1 && field.length && !isNS( field ) && field || arguments,
										tr = jsam.documentPane.children( '.tab-page' ).children( 'table' ).add( '.tab-page > div.tmplvars table' ).children( 'tbody' ).children( 'tr' )
											.filter( 'tr:has( > td:has( > .warning, > .sectionHeader ) )' );
									return !arr.length || ( arr.length == 1 && arr[ 0 ] == false ) ? tr : tr
										.filter(
											function(){
												return $.inArray( $( ' > td:first', this ).children( '.warning, .sectionHeader' ).text().trim(), arr ) !== -1;
											}
										);
								},
								{
								
									/*
									** @name:
									**   hide
									** @path:
									**   jsam => document => field => hide
									** @api:
									**   jsam.document.field.hide( id );
									** @description:
									**   Скрыть поле(я) по его имени
									** @param "id":
									**   Название поля или массив названий полей. Пример: "Title" или [ "Description", "Resource content" ]
									** @returns:
									**   jQuery Object - скрытое поле(я)
									** @example:
									**   jsam.document.field.hide();                                     // Скрыть все поля
									**   jsam.document.field.hide( "Title" );                            // Скрыть поле с названием "Title"
									**   jsam.document.field.hide( "Resource content", "Description" );  // Скрыть поля с названиями "Resource content", "Description"
									*/
									hide: function(){
										return jsam.document.field.apply( this, arguments ).hide();
									},
									
									/*
									** @name:
									**   decomposed
									** @path:
									**   jsam => document => field => decomposed
									** @api:
									**   jsam.document.field.decomposed( id );
									** @description:
									**   Получить информацию о поле(ях) массивом объектов информации
									** @param "id":
									**   Название поля или массив названий полей. Пример: "Title" или [ "Description", "Resource content" ]
									** @returns:
									**   Array - массив объектов информации о поле
									** @example:
									**   jsam.document.field.decomposed();                                    // Получить информацию по всем полям
									**   jsam.document.field.decomposed( "Resource content", "Description" ); // Получить информацию по полям "Resource content" и "Description"
									*/
									decomposed: function(){
										return jsam.document.field.apply( this, arguments )
											.map(
												function(){
													var
														_      = $( this ),
														td     = _.children( 'td' ),
														first  = td.eq( 0 ),
														last   = td.eq( -1 ),
														size   = td.size(),
														type   = size == 1 && first.is( '[colspan=2]' ) ? 2 : size == 2 ? 1 : 3,
														input  = _.find( '[name]' ).eq( 0 ),
														name   = input.attr( 'name' );
													return {
														tr     : _,
														td     : td,
														first  : first,
														last   : last,
														title  : type == 1 ? first : first.children( '.sectionHeader' ).eq( 0 ),
														box    : type == 1 ? last : first.children( '.sectionBody' ).eq( 0 ),
														help   : _.find( 'img.tooltip' ),
														input  : input,
														name   : name,
														type   : type,
														size   : size
													};
												}
											)
											.toArray();
									},
									
									view: function( id, type ){
										type == type != 1 ? 2 : 1;
										return jsam.document.field( id )
											.each(
												function(){
													var
														$this = $( this ),
														td = $this.children( 'td' ),
														$type = td.size() == 1 && td.is( '[colspan=2]' ) ? 2 : 1,
														first = td.first(),
														last = td.last(),
														title = first.children( $type == 1 ? '.warning' : '.sectionHeader' ).eq( 0 ).contents(),
														box = $type == 1 ? last.contents() : first.children( '.sectionBody' ).eq( 0 ).contents(),
														help;
													if( type == $type ){
														return;
													}
													help = $this.find( 'img.tooltip' ).eq( 0 ).detach();
													if( type == 1 ){
														first
														.removeAttr( 'colspan' )
														.after( '<td/>' )
														.next()
														.html( box )
														.append( help )
														.prev()
														.html( $( '<span/>', { className: "warning", html: title } ) );
													}
													else if( type == 2 ){
														last.detach();
														first
														.attr( 'colspan', 2 )
														.html( '<div class="sectionHeader"></div><div class="sectionBody"></div>' )
														.children( 'div' )
														.eq( 1 )
														.html( box )
														.prev()
														.html( title.find( '*' ).size() == 0 ? title[ 0 ].data.trim() + ' ' : title.append( ' ' ) )
														.append( help );
													}
												}
											);
									},
									
									/*
									** @name:
									**   rename
									** @path:
									**   jsam => document => field => rename
									** @api:
									**   jsam.document.field.rename( id, name );
									** @description:
									**   Переименовать поле
									** @param "id":
									**   Название поля или массив названий полей. Пример: "Title" или [ "Description", "Resource content" ]
									**   Cтрока или массив строк
									** @returns:
									**   jQuery Object - переименованное поле(я)
									** @example:
									**   jsam.document.field.rename( false, "Поле" );                        // Переименовать все поля в "Поле"
									**   jsam.document.field.rename( "Описание", "Аннотация" );              // Переименовать поле "Описание" в "Аннотация"
									**   jsam.document.field.rename( [ "Заголовок", "Описание" ], "Что?" );  // Переименовать поля "Заголовок" и "Описание" в "Что?"
									*/
									rename: function( id, name ){
										return jsam.document.field( id )
											.each(
												function(){
													$( '.warning, .sectionHeader', this ).eq( 0 ).html( name );
												}
											);
									},
									
									/*
									** @name:
									**   width
									** @path:
									**   jsam => document => field => width
									** @api:
									**   jsam.document.field.width( size );
									** @description:
									**   Задать ширину названия полей
									** @param "names":
									**   Ширина названия
									** @param "size":
									**   Ширина в процентак, пикселях и т. д.
									**   Строка или число
									** @returns:
									**   jQuery Object - теги td с изменённой шириной
									** @example:
									**   jsam.document.field.width( 200 );     // Задать ширину названий полей в 200 пикселей
									**   jsam.document.field.width( '40%' );   // Задать ширину названий полей в 40%
									**   jsam.document.field.width( '20em' );  // Задать ширину названий полей в 20em
									*/
									width: function( size ){
										return jsam.document.field()
											.children( 'td:not( td[colspan!=2] + td )' )
											.removeAttr( 'width' )
											.width( jsam.document.field.width.size = size );
									}
									
								}
								
							),
									
							/*
							** @name:
							**   help
							** @path:
							**   jsam => document => help
							** @api:
							**   jsam.document.help( multiparams );
							** @description:
							**   Получить тег изображение подсказки, которая появляется рядом с каждым параметром ресурса, когда курсор наводится на иконку помощи
							** @param "multiparams":
							**   Название поля(пример: "Заголовок"), подсказку которого нужно получить
							**   В функцию передаётся несколько строк или один массив строк
							** @returns:
							**   jQuery Object - подсказка(и)
							** @example:
							**   jsam.document.help();                                     // Получить все подсказки
							**   jsam.document.help( "Заголовок" );                        // Получить подсказку поля "Заголовок"
							**   jsam.document.help( "Описание", "Псевдоним" );            // Получить подсказки полей "Описание" и "Псевдоним"
							*/
							help: extend(
								function(){
									return jsam.document.field.apply( this, arguments ).find( 'img.tooltip' );
								},
								{
									
									/*
									** @name:
									**   hide
									** @path:
									**   jsam => document => help => hide
									** @api:
									**   jsam.document.help.hide( multiparams );
									** @description:
									**   Скрыть подсказку
									** @param "multiparams":
									**   Название поля(пример: "Заголовок"), подсказку которого нужно скрыть
									**   В функцию передаётся несколько строк или один массив строк
									** @returns:
									**   jQuery Object - скрытая подсказка(и)
									** @example:
									**   jsam.document.help.hide();                                     // Скрыть все подсказки
									**   jsam.document.help.hide( "Заголовок" );                        // Скрыть подсказку поля "Заголовок"
									**   jsam.document.help.hide( "Описание", "Псевдоним" );            // Скрыть подсказки полей "Описание" и "Псевдоним"
									*/
									hide: function(){
										return jsam.document.help.apply( window, arguments ).hide();
									},
									
									/*
									** @name:
									**   change
									** @path:
									**   jsam => document => help => change
									** @api:
									**   jsam.document.help.change( field, text );
									** @description:
									**   Сменить текст подсказки/Добавить подсказку к полю
									** @param "field":
									**   Название поля(пример: "Заголовок"), подсказку которого нужно переименовать/подсказку к которому нужно добавить
									** @param "text":
									**   Текст подсказки
									** @returns:
									**   jQuery Object - подсказка
									** @example:
									**   jsam.document.help.change( "Заголовок", "Заголовок страницы" );   // У поля "Заголовок" сменить текст подсказки на "Заголовок страницы"
									**   jsam.document.help.change( "Содержимое ресурса", "Контент документа" );   // К полю "Содержимое ресурса" добавить подсказку с текстом "Контент документа"
									*/
									change: function( field, text ){
										var
											tr = jsam.document.field( field ),
											img = $(
												'<img/>',
												{
													'title' : text,
													'alt'   : text,
													'src'   : 'media/style/MODxCarbon/images/icons/b02_trans.gif',
													'class' : 'tooltip',
													'css'   : {
														'cursor': 'help'
													}
												}
											),
											td = tr.children( 'td' ),
											tooltip = tr.find( 'img.tooltip' );
										tooltip.length ? tooltip.replaceWith( img )
											: td.length == 1 && td.is( '[colspan=2]' ) ? td.children( '.sectionHeader:first' ).append( '&nbsp;' ).append( img )
											: td.last().append( img );
										!window.ie6 ? new Tips( img[ 0 ], { className: 'custom' } )
											: img.attr(
												{
													'onmouseover': "this.src='media/style/MODxCarbon/images/icons/b02.gif';",
													'onmouseout': "this.src='media/style/MODxCarbon/images/icons/b02_trans.gif';",
													'onclick': "alert(this.alt);"
												}
											);
										return img;
									}
									
								}
							),
							
							/*
							** @name:
							**  split
							** @path:
							**   jsam => document => split
							** @api:
							**   jsam.document.split( multiparams );
							** @description:
							**   Получить разделители полей
							** @param "multiparams":
							**   Название поля(пример: "Заголовок"), разделитель под которым нужно получить
							**   В функцию передаётся несколько строк или один массив строк
							** @returns:
							**   jQuery Object - разделители
							** @example:
							**   jsam.document.split();                                          // Получить все разделители
							**   jsam.document.split( "Дата отмены публикации" );                // Получить разделитель под полем "Дата отмены публикации"
							**   jsam.document.split( "Дата", "Местонахождение содержимого" );   // Получить разделители под полями "Дата" и "Местонахождение содержимого"
							*/
							split: extend(
								function(){
									return jsam.document.field.apply( window, arguments )
										.next()
										.filter( ':has( > td[colspan=2] > div.split )' );
								},
								{
									
									/*
									** @name:
									**  add
									** @path:
									**   jsam => document => split => add
									** @api:
									**   jsam.document.split.add( multiparams );
									** @description:
									**   Добавить разделители полей под определёнными полями
									** @param "multiparams":
									**   Название поля(пример: "Заголовок"), разделитель под которым нужно добавить
									**   В функцию передаётся несколько строк или один массив строк
									** @returns:
									**   jQuery Object - вновь добавленные разделители
									** @example:
									**   jsam.document.split.add();                             // Добавить разделители под всеми полями
									**   jsam.document.split.add( "Заголовок" );                // Добавить разделители под полем "Заголовок"
									**   jsam.document.split.add( "Описание", "Псевдоним" );    // Добавить разделители под полями "Описание" и "Псевдоним"
									*/
									add: function(){
										return jsam.document.field.apply( window, arguments )
											.next()
											.not( 'tr:has( > td[colspan=2] > div.split )' )
											.before( '<tr><td colspan="2" valign="top"><div class="split"></div></td></tr>' );
									},
									
									/*
									** @name:
									**  remove
									** @path:
									**   jsam => document => split => remove
									** @api:
									**   jsam.document.split.remove( multiparams );
									** @description:
									**   Удалить разделители полей под определёнными полями
									** @param "multiparams":
									**   Название поля(пример: "Заголовок"), разделитель под которым нужно удалить
									**   В функцию передаётся несколько строк или один массив строк
									** @returns:
									**   jQuery Object - удалённые разделители
									** @example:
									**   jsam.document.split.remove();                                          // Удалить все разделители
									**   jsam.document.split.remove( "Дата отмены публикации" );                // Удалить разделитель под полем "Дата отмены публикации"
									**   jsam.document.split.remove( "Дата", "Местонахождение содержимого" );   // Удалить разделители под полями "Дата" и "Местонахождение содержимого"
									*/
									remove: function(){
										return jsam.document.split.apply( this, arguments ).detach();
									}
									
								}
							)
							
						}
					),
					
					/*
					** @name:
					**   tree
					** @path:
					**   jsam => tree
					** @api:
					**   jsam.tree( fn );
					** @description:
					**   Передать на выполнение функцию с правилами настройки ДЕРЕВА РЕСУРСОВ. Функция выполняется только в фрейме типа "tree"
					** @param "fn":
					**   Функция, выполняемая при загрузке фрейма типа "tree". Функция содержит в себе правила нстройки
					** @returns:
					**   jsam.tree
					** @example:
					**   jsam.tree(function( data, jQuery, log ){
					**     this.hide( 2 );
					**   });
					*/
					tree: extend(
						// Псевдо-назначение jQuery объекта
						function( fn ){
							return fn && jsam.fns.push( function( data ){ data.type == 'tree' && fn.apply( this, arguments ); } ) && jsam.tree;
						},
						{					
						
							/*
							** @name:
							**  hide
							** @path:
							**   jsam => tree => hide
							** @api:
							**   jsam.tree.hide( id );
							** @description:
							**   Скрыть определённый ресурс из виду
							** @param "id":
							**   ID скрываемого ресурса
							** @returns:
							**   jQuery Object - скрытый ресурс
							** @example:
							**   jsam.tree.hide( 1 );        // Скрыть первый ресурс
							*/
							hide: function( id ){
								return $( '#node' + id ).hide();
							}
						
						}
					),
					
					/*
					** @name:
					**   chunk
					** @path:
					**   jsam => chunk
					** @api:
					**   jsam.chunk( fn );
					** @description:
					**   Передать на выполнение функцию с правилами настройки СТРАНИЦЫ РЕДАКТИРОВАНИЯ ЧАНКА. Функция выполняется только в фрейме типа "chunk"
					** @param "fn":
					**   Функция, выполняемая при загрузке фрейма типа "chunk". Функция содержит в себе правила нстройки
					** @returns:
					**   jsam.chunk
					** @example:
					**   jsam.chunk(function( data, jQuery, log ){
					**     this.hide.actions();
					**   });
					*/
					chunk: extend(
						// Псевдо-назначение jQuery объекта
						function( fn ){
							return fn && jsam.fns.push( function( data ){ data.type == 'chunk' && fn.apply( this, arguments ); } ) && jsam.chunk;
						},
						{					
						
							/*
							** @name:
							**  hide
							** @path:
							**   jsam => chunk => hide
							** @api:
							**   jsam.chunk.hide;
							** @description:
							**   Объект с функциями скрытия элементов
							** @returns:
							**   Object
							** @example:
							**   jsam.chunk.hide;
							*/
							hide: {
								
								/*
								** @name:
								**   actions
								** @path:
								**   jsam => chunk => hide => actions
								** @api:
								**   jsam.chunk.hide.actions();
								** @description:
								**   Скрыть кнопки управления чанком из виду
								** @returns:
								**   jQuery Object - контейнер кнопок управления чанком
								** @example:
								**   jsam.chunk.hide.actions();
								*/
								actions: function(){
									return $( '#actions' ).hide();
								},
								
								/*
								** @name:
								**   settings
								** @path:
								**   jsam => chunk => hide => settings
								** @api:
								**   jsam.chunk.hide.settings();
								** @description:
								**   Скрыть поля настройки чанка
								** @returns:
								**   jQuery Object - контейнер полей настройки чанка
								** @example:
								**   jsam.chunk.hide.settings();
								*/
								settings: function(){
									return $( '#mutate > .sectionBody' ).eq( 0 ).children( 'table' ).eq( 0 ).hide();
								}
								
							}
						
						}
					)
					
				}
			),
			
			// Быстрая ссылка на объект данных фрейма
			data = jsam.data,
			
			// Быстрая ссылка на тип фрейма
			type = jsam.type = data.type,
			
			// Быстрая ссылка на объект для работы с фреймом
			obj = jsam[ type ],
			
			// Превращение id в номер
			id = data.id = parseInt( data.id || 0 ),
			
			lang = jsam.translate,
			
			isWorkFrame = jsam.isWorkFrame = !!( type != 'tree' && type != 'menu' ),
			isDocument = jsam.isDocument = type == 'document';
		
		/*
		** Назначение обработчика события на полную загрузку фрейма
		*/
		$( window ).load(
			function(){
				
				/*
				** Создание быстрых ссылок
				*/
				var
					
					// Фрейм "menu" - jQuery-ссылка на навигацию
					nav = jsam.menu.nav = $( '#nav' ),
					tab,
					documentPane = jsam.documentPane = $( '#documentPane' ),
					
					// Ссылка на оверлей-прелоадер
					overlay = $( '#jsamOverlay' ),
					// Существует ли оверлей-прелоадер?
					isOverlay = !!overlay.length,
					
					mutate = document.mutate,
					m = $( mutate );
				
				/*
				** Считывание данных документа и занесение их в объект для дальнейшего использования
				*/
				if( mutate ){
					temp = {};
					m.find( 'input[name], textarea[name]' )
					.each(
						function(){
							var val = this.type == 'checkbox' ? this.checked : this.value;
							temp[ this.name ] = typeof val == 'string' && /^[0-9\.]+$/.test( val ) ? parseFloat( val ) : val;
						}
					);
					data = jsam.data = extend( temp, data );
				}
				
				
				if( isWorkFrame ){
					
					/*
					** Создание объекта для управления табами
					*/
					if( $( '.tab-row' ).length ){
						obj.tab = jsam.tab();
					}
					
					/*
					** Работа с tinyMCE
					*/
					if( window.tinyMCE ){
						tinyMCE.execCommand( 'mceResetDesignMode' );
						$( 'span.mceEditor iframe[id$="_ifr"]' )
						.each(
							function(){
								var
									id = this.getAttribute( 'id' ).replace( /_.+$/, '' ),
									area = $( '#' + id ).data( 'tinyMCE', {} );
								tinyMCE.execCommand( 'mceRemoveControl', false, id );
							}
						);
					}
					
				}
				
				
				/*
				** Поправление дерева DOM-дерева страницы редактирования ресурса для полной совместимости с функциями управления фреймом
				*/
				if( isDocument ){
					
					/*
					** Разделение в разные tr теги полей menuindex и hidemenucheck
					*/
					var
						table = $( '[name="menuindex"]' ).parents( 'table:first' ),
						tr = table.parents( 'tr:first' ),
						new_tr;
					table.detach();
					tr.after( new_tr = tr.clone() ).find( 'td:last' ).html( table.find( 'td:first' ).contents() );
					new_tr.find( 'td:first' ).html( table.find( '.warning' ) ).next().html( table.find( 'td:last' ).contents() );
					
					/*
					** Помещение поля "Содержимое ресурса" в тег tr
					*/
					documentPane
						.find( 'textarea#ta' )
						.each(
							function(){
								documentPane
									.find( 'table:first tr:last' )
									.after(
										$( '<tr/>', { html: '<td colspan="2"></td>' } )
									)
									.next()
									.find( 'td' )
									.append(
										$( this ).parents( '.sectionBody:first' ).prev().andSelf()
									);
							}
						);
					
					/*
					** Добавление формата даты в тот же tr, где находится поле
					*/
					$( 'input.DatePicker' )
					.each(
						function(){
							var
								$this = $( this ),
								tr = $this.parents( 'tr:first' ),
								next = tr.next();
							if( next.find( 'td:first' ).text() == '' ){
								$this.parent().append( $( '<div/>' ).html( next.find( 'td:last' ).contents() ) );
								next.detach();
							}
						}
					);
					
					/*
					** Добавление тегам td вертикального выравнивания по верху
					*/
					$( '#mutate tr > td' ).attr( 'valign', 'top' );
					
				}
				
				
				/* *******************
				** Модификация функций
				*/
				
				/*
				** SetUrl
				*/
				if( !window.SetUrl ){
					window.SetUrl = function( url ){
						if( window.lastFileCtrl ){
							var c = mutate[ window.lastFileCtrl ];
							if( c ){
								c.value = url;
								lastFileCtrl = '';
							}
						}
						else if( lastImageCtrl ){
							var c = mutate[ window.lastImageCtrl ];
							if( c ){
								c.value = url;
								lastImageCtrl = '';
							}
						}
					};
				}
				if( window.SetUrl && !SetUrl.modifed ){
					var s = SetUrl;
					SetUrl = function(){
						if( window.browseFn ){
							window.browseFn.apply( this, arguments );
							window.browseFn = false;
						}
						else{
							s.apply( this, arguments );
						}
					}
					SetUrl.modifed = true;
					SetUrl.SetUrl = s;
				}
				/*
				** OpenServerBrowser
				*/
				if( !window.OpenServerBrowser ){
					OpenServerBrowser = function( url, width, height ){
						var
							left = ( screen.width  - width ) / 2,
							top = ( screen.height - height ) / 2,
							options = 'toolbar=no,status=no,resizable=yes,dependent=yes,width=' + width + ',height=' + height + ',left=' + left + ',top=' + top,
							oWindow = window.open( url, 'FCKBrowseWindow', options );
					}
				}
				/*
				** OpenServerBrowser
				*/
				if( !window.OpenServerBrowser ){
					OpenServerBrowser = function( url, width, height ){
						var
							left = ( screen.width  - width ) / 2,
							top = ( screen.height - height ) / 2,
							options = 'toolbar=no,status=no,resizable=yes,dependent=yes,width=' + width + ',height=' + height + ',left=' + iLeft + ',top=' + iTop,
							oWindow = window.open( url, 'FCKBrowseWindow', options );
					};
				}
				window.Browse = function( type ){
					OpenServerBrowser(
						'/manager/media/browser/mcpuk/browser.html?Type=' + ( isString( type ) ? type : 'files' ) + '&Connector=/manager/media/browser/mcpuk/connectors/php/connector.php&ServerPath=/',
						screen.width * 0.7,
						screen.height * 0.7
					);
				};
				
				
				
				/*
				** Печатание отчёта в консоль Firebug
				*/
				console.groupCollapsed( lang( 'JSAM успешно подключился во фрейм типа' ) + ' "' + type + '"' );
				console.groupCollapsed( lang( 'Информация о фрейме' ) );
				log(
					lang( 'Тип фрейма' )                          + ": ", type,
					"\n" + lang( 'Фрейм' )                        + ": ", window,
					"\n" + "Url"                                  + ": ", document.location.href,
					"\n" + lang( 'Объект' ) + " JSAM"             + ": ", { jsam: jsam },
					"\n" + lang( 'Объект для работы с фреймом' )  + ": ", { object: obj },
					"\n" + lang( 'Количество тегов во фрейме' )   + ": ", $( '*' ).length
				)
				console.groupEnd();
				console.groupCollapsed( lang( 'Информация о версиях' ) );
				log(
					[
						"jQuery: " + $.fn.jquery,
						"JSAM: "   + jsam.version,
						"MODx: "   + jsam.data.config.modx
					]
					.join( "\n" )					
				);
				console.groupEnd();
				console.info( lang( 'Данные фрейма' ) + ': ', data )
				console.groupEnd();
				
				/*
				** Начало старта замера времени выполнения правил
				*/
				console.time( lang( 'Время выполнения правил' ) );				
				
				/*
				** Выполнение правил пользователя
				*/
				if( type != 'tree' ){
					$.each(
						jsam.fns,
						function(){
							this.call( obj, data, $, log );
						}
					);
				}
				else{
					setInterval(
						function(){
							$.each(
								jsam.fns,
								function(){
									this.call( obj, data, $, log );
								}
							);
						},
						500
					);
				}
				
				/*
				** Конец замера времени выполнения правил и его пропечатывание в консоли
				*/
				console.timeEnd( lang( 'Время выполнения правил' ) );
				
				
				/*
				** Восстановление tinyMCE редакторов
				*/
				$( 'textarea' )
				.each(
					function(){
						var _ = $( this ), id = this.id, o = _.data( 'tinyMCE' );
						if( o instanceof Object ){
							tinyMCE.execCommand( 'mceAddControl', false, id );
							tinyMCE.execCommand( 'mceFocus', false, id );
						}
					}
				);
				
				/*
				** Скрытие JSAM-прелоадера
				*/
				overlay
				.fadeOut(
					400,
					function(){
						
						/*
						** Удаление прелоадера из документа
						** "Очистка окружающей среды" =)
						*/
						overlay.remove();
						
					}
				);
				
				// Чистка
				$( '.jsam-remove' ).remove();
				temp = $( '.tmplvars' ).eq( 0 );
				if( !temp.find( 'tr' ).length ){
					temp.prev().andSelf().detach();
				}
				
			}
		);
		
	}
)( window, top, window.document, window.jsam );

/*
** vFls - Файл-виджет плагина JSAM
** @version 0.0.1alpha
** @description: JavaScript-виджет плагина JSAM для превращения поля в интерактивный менеджер файлов
** @author: Александр Николаевич Кузнецов aka Regent(http://vl.vg/)
** @temp_home_page: http://vj.vg/
** Dual licensed under the MIT and GPL licenses.
** - http://www.opensource.org/licenses/mit-license.php
** - http://www.gnu.org/copyleft/gpl.html
*/
(
	function( window, document, jsam, $, log ){
		
		/*
		** @name:
		**   vFls
		** @path:
		**   jsam => widget => vFls
		** @api:
		**   jsam.widjet.vFls( options );
		** @description:
		**   Применить к контейнеру виджет vFls
		** @returns:
		**   Object - опции с методами виджета
		** @example:
		**   jsam.widget.vFls({ box:$('[name="longtitle"]').parent(), name:'longtitle' });
		*/
		jsam.widget.vFls = function( options ){
			// Проверка входных данных
			if( !options || !options.box ){
				return false;
			}
			options.box = $( options.box );
			if( !options.box.length ){
				return false;
			}
			
			/*
			** Основные переменные
			*/
			var
			
				// Быстрая ссылка на виджет
				fls = jsam.widget.vFls,
				
				// Основные опции
				o = $.extend( {}, fls.options, options ),
				
				// Контейнер виджета
				box = o.box.data( 'vFls', o ),
				
				// Начальное значение виджета
				value = box.find( ':text, textarea' ).eq( 0 ).val(),
				name = o.name = o.name || box.find( '[name]' ).attr( 'name' ),
				contents = o.contents = box.contents().detach(),
				input = $(
					'<input/>',
					{
						type: 'text',
						id: name,
						name: name,
						value: ''
					}
				),
				add = o.add = function( url ){
					o.fileBox.append(
						$( '<div/>' )
						.attr( 'class', 'vFls-file' )
						.append(
							$( '<div/>' )
							.attr( 'class', 'vFls-control' )
							.append(
								$(
									'<a/>',
									{
										className: 'vFls-button vFls-view',
										html: $( '<img/>' ).attr( 'src', 'media/style/MODxCarbon/images/icons/preview.png' ),
										href: '#',
										target: '_blank'
									}
								),
								$(
									'<span/>',
									{
										className: 'vFls-button vFls-remove',
										html: $( '<img/>' ).attr( 'src', 'media/style/MODxCarbon/images/icons/cancel.png' ),
										click: function(){
											var _ = $( this ).parent().parent();
											_.slideUp(
												300,
												function(){
													window.documentDirty = true;
													_.remove();
													parse();
												}
											);
										}
									}
								),
								$(
									'<span/>',
									{
										className: 'vFls-button vFls-up',
										html: $( '<img/>' ).attr( 'src', 'media/style/MODxCarbon/images/icons/arrow_up.png' ),
										click: function(){
											var
												_ = $( this ).parent().parent(),
												files = _.parent().children(),
												size = files.length,
												index = files.index( _ );
											if( index != 0 && size > 1 ){
												_.prev().before( _ );
												_.hide().fadeIn( 300 );
												window.documentDirty = true;
												parse();
												this.blur();
											}
										}
									}
								),
								$(
									'<span/>',
									{
										className: 'vFls-button vFls-down',
										html: $( '<img/>' ).attr( 'src', 'media/style/MODxCarbon/images/icons/arrow_down.png' ),
										click: function(){
											var
												_ = $( this ).parent().parent(),
												files = _.parent().children(),
												size = files.length,
												index = files.index( _ );
											if( index != size - 1 && size > 1 ){
												_.next().after( _ );
												_.hide().fadeIn( 300 );
												window.documentDirty = true;
												parse();
												this.blur();
											}
										}
									}
								)
							),
							$( '<div/>' ).attr( 'class', 'vFls-url' ).text( url )
						)						
					)
					.children()
					.eq( -1 )
					.hide()
					.slideDown( 350 )
					.find( 'a.vFls-view' )
					.attr( 'href', '/' + url )
					parse();
				},
				parse = o.parse = function(){
					input[ 0 ].value = o.fileBox.children( '.vFls-file' ).children( '.vFls-url' )
						.map(
							function(){
								return $( this ).text()
							}
						)
						.toArray()
						.join( '||' );
				},
				temp, size;
			
			box
			.addClass( 'vFls' )
			.append(
				$(
					'<span/>',
					{
						className: 'vFls-browse vFls-button',
						html: '<img src="media/style/MODxCarbon/images/icons/add.png">Добавить файл',
						click: function(){
							window.browseFn = function( url ){
								o.add( url );
							};
							Browse();
						}
					}
				),
				o.fileBox = $( '<div/>' ).attr( 'class', 'vFls-file-box' ),
				input.hide()
			);
			
			if( typeof value == 'string' && value != '' ){
				$.each(
					value = value.split( '||' ),
					function( i ){
						add( value[ i ] );
					}
				);
			}
			
			return o;
		};
		
		jsam.widget.vFls.options = {
			max: 0
		};
		
		/*
		** @name:
		**   vFls
		** @path:
		**   jsam => document => vFls
		** @api:
		**   jsam.document.vFls( id );
		** @description:
		**   Применить к полю виджет vFls
		** @param "id":
		**   Название поля или массив названий полей. Пример: "Title" или [ "Description", "Resource content" ]
		** @returns:
		**   jQuery Object - поля, к которым применён виджет vFls
		** @example:
		**   jsam.document.vFls( [ "Расширенный заголовок", "Содержимое ресурса" ] ); // Применить виджет к полям "Расширенный заголовок" и "Содержимое ресурса"
		*/
		jsam.document.vFls = function( id ){
			return $( jsam.document.field.decomposed( id ) )
				.map(
					function(){
						jsam.widget.vFls(
							{
								box: this.box,
								name: this.name
							}
						);
						return this.tr[ 0 ];
					}
				);
		};
		
	}
)( window, document, window.jsam, window.jsam.$, jsam.log );